﻿using Basic.FlowApplication.Interface;
using Basic.FlowApplication.Model;
using Basic.FlowApplication.Model.Flow;
using Basic.FlowApplication.Model.FlowEvent;
using Basic.FlowCollect;
using Basic.FlowModel.AuditEmp;
using Basic.FlowModel.DB;
using Basic.FlowModel.Node;
using Basic.FlowModel.NodeDataRelation;
using Basic.FlowModel.NodeFormPower;
using Basic.FlowModel.NodeRoute;
using Basic.FlowRemoteModel;
using Basic.FlowRemoteModel.NodeFormData.Model;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.Client;
using WeDonekRpc.Helper;

namespace Basic.FlowApplication.lmpl
{
    public class FlowNodeService : IFlowNodeService
    {
        private readonly IFlowCollect _Flow;
        private readonly IFlowNodeCollect _Node;
        private readonly INodeAuditEmpCollect _AuditEmp;
        private readonly INodeMsgCollect _NodeMsg;
        private readonly INodeRouteCollect _NodeRoute;
        private readonly INodeEventCollect _NodeEvent;
        private readonly ILocalCacheController _LocalCache;
        private readonly INodeFormDataRelationCollect _DataRelation;
        private readonly INodeFormPowerCollect _FormPower;
        public FlowNodeService ( IFlowNodeCollect node,
            INodeAuditEmpCollect auditEmp,
            INodeMsgCollect nodeMsg,
            IFlowCollect flow,
            INodeRouteCollect nodeRoute,
            ILocalCacheController cache,
            INodeFormDataRelationCollect relation,
            INodeFormPowerCollect power,
            INodeEventCollect nodeEvent )
        {
            this._FormPower = power;
            this._DataRelation = relation;
            this._Flow = flow;
            this._LocalCache = cache;
            this._Node = node;
            this._AuditEmp = auditEmp;
            this._NodeMsg = nodeMsg;
            this._NodeRoute = nodeRoute;
            this._NodeEvent = nodeEvent;
        }

        public AuditFlowBody Get ( long flowId )
        {
            string key = "FlowBody_" + flowId;
            if ( !this._LocalCache.TryGet(key, out AuditFlowBody body) )
            {
                body = this._Get(flowId);
                _ = this._LocalCache.Set(key, body, DateTime.Now.AddHours(12));
            }
            if ( body.Status != FlowStatus.启用 )
            {
                throw new ErrorException("flow.no.enable");
            }
            return body;
        }

        public AuditFlowBody Get ( long flowId, string ver )
        {
            long id = this.FindId(flowId, ver);
            return this.Get(id);
        }
        private long FindId ( long flowId, string ver )
        {
            string key = "FlowVer_" + flowId + "_" + ver;
            if ( !this._LocalCache.TryGet(key, out long id) )
            {
                id = this._Flow.GetFlowId(flowId, ver);
                _ = this._LocalCache.Set(key, id, DateTime.Now.AddHours(12));
            }
            return id;
        }
        private AuditFlowBody _Get ( long flowId )
        {
            FlowDto flow = this._Flow.Get<FlowDto>(flowId);
            AuditFlowBody body = new AuditFlowBody
            {
                DefFormId = flow.DefFormId,
                FlowName = flow.FlowName,
                Status = flow.Status,
                Id = flow.Id
            };
            if ( body.Status != FlowStatus.启用 )
            {
                return body;
            }
            FormColPowerDto[] powers = this._FormPower.GetsByFlowId(flowId);
            NodeData[] nodes = this._Node.Gets<NodeData>(flowId);
            DataRelationDto[] relations = nodes.IsExists(a => a.FormId.HasValue) ? this._DataRelation.GetsByFlowId<DataRelationDto>(flowId) : null;
            FlowNode[] datas = nodes.OrderBy(a => a.NodeLvl).ConvertMap<NodeData, FlowNode>();
            DBFlowNodeAuditEmp[] audits = this._AuditEmp.Gets<DBFlowNodeAuditEmp>(flowId);
            DBFlowNodeMsg[] msgs = this._NodeMsg.Gets<DBFlowNodeMsg>(flowId);
            NodeEvent[] evs = this._NodeEvent.Gets<NodeEvent>(flowId);
            RouteBase[] toNodes = this._NodeRoute.Gets<RouteBase>(flowId);
            Dictionary<long, FlowNodeType> nodeType = datas.ToDictionary(a => a.Id, a => a.NodeType);
            body.IsShowSign = nodes.IsExists(c => c.IsUpFileSign);
            datas.ForEach(c =>
            {
                c.AuditEmp = audits.ConvertFind<DBFlowNodeAuditEmp, NodeAuditEmpSet>(a => a.NodeId == c.Id);
                c.Msgs = msgs.ConvertMap<DBFlowNodeMsg, NodeMsg>(a => a.NodeId == c.Id);
                c.MsgEvent = evs.Where(a => a.NodeId == c.Id).ToDictionary(a => a.EventType, a => a.EventId);
                c.ToNodeId = toNodes.Convert(a => a.NodeId == c.Id, a => a.ToNodeId);
                c.PrevNodeId = toNodes.Convert(a => a.ToNodeId == c.Id, a => a.NodeId);
                if ( c.FormId.HasValue )
                {
                    c.Relation = relations.Where(a => a.NodeId == c.Id).Select(a => new DataRelation
                    {
                        ColId = a.ColId,
                        FormId = a.FormId,
                        ToColId = a.ToColId
                    }).ToArray();
                }
                c.ColPower = powers.Where(a => a.NodeId == c.Id).ToDictionary(a => a.ColId, a => a.Operate);
            });
            body.BeginNode = nodes.Find(a => a.NodeType == FlowNodeType.开始节点, a => a.Id);
            body.Nodes = datas.ToDictionary(a => a.Id, a => a);
            this._InitSubFlow(body.BeginNode, body, datas, new long[] { body.BeginNode });
            return body;
        }
        private void _InitSubFlow ( long id, AuditFlowBody body, FlowNode[] datas, long[] prtId )
        {
            FlowNode node = body.Nodes[id];
            if ( node.ParentId == null )
            {
                node.ParentId = prtId;
            }
            else
            {
                node.ParentId = node.ParentId.Concat(prtId).Distinct().ToArray();
            }
            prtId = prtId.Add(id);
            node.ToNodeId.ForEach(c =>
            {
                this._InitSubFlow(c, body, datas, prtId);
            });
        }
    }
}
